package com.c2b.algorithm.leetcode.hot100;

/**
 * <a href="https://leetcode.cn/problems/jump-game/description/">跳跃游戏</a>
 * <p>给定一个非负整数数组 nums ，你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标。</p>
 * <pre>
 * 示例 1：
 *      输入：nums = [2,3,1,1,4]
 *      输出：true
 *      解释：可以先跳 1 步，从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
 *
 * 示例 2：
 *      输入：nums = [3,2,1,0,4]
 *      输出：false
 *      解释：无论怎样，总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 ， 所以永远不可能到达最后一个下标。
 * </pre>
 * <b>提示：</b>
 * <li>1 <= nums.length <= 3 * 10^4</li>
 * <li>0 <= nums[i] <= 10^5</li>
 *
 * @author c2b
 * @since 2023/4/25 15:53
 */
public class Hot055CanJump_M {

    /**
     * 贪心算法
     * <p>
     * 设想一下，对于数组中的任意一个位置y，我们如何判断它是否可以到达？
     * 根据题目的描述，只要存在一个位置 x，x本身可达的，并且它跳跃的最大长度为 x+nums[x]，这个值大于等于 y，即 x+nums[x]≥y，那么位置 y 也可以到达。
     * <p>
     * 换句话说，对于每一个可以到达的位置 x，它使得 x+1,x+2,⋯,x+nums[x]这些连续的位置都可以到达。
     * <p>
     * 这样以来，我们依次遍历数组中的每一个位置，并实时维护 最远可以到达的位置。对于当前遍历到的位置 x，如果它在 最远可以到达的位置 的范围内，那么我们就可以从起点通过若干次跳跃到达该位置，因此我们可以用 x+nums[x]更新 最远可以到达的位置。
     * <p>
     * 在遍历的过程中，如果 最远可以到达的位置 大于等于数组中的最后一个位置，那就说明最后一个位置可达，我们就可以直接返回 True 作为答案。反之，如果在遍历结束后，最后一个位置仍然不可达，我们就返回 False 作为答案。
     */
    public boolean canJump(int[] nums) {
        int len = nums.length;
        // 目前可以跳到的最远距离
        int mostRight = 0;
        for (int i = 0; i < len; i++) {
            // 判断之前的任一位置是否可以跳到当前位置
            if (i <= mostRight) {
                // 如果可以跳到当前位置，更新可以跳跃的最远距离
                mostRight = Math.max(mostRight, i + nums[i]);
                // 如果跳跃的最远距离大于等于最终位置。则返回true，否则返回false
                if (mostRight >= len - 1) {
                    return true;
                }
            }
        }
        return false;
    }
}
